# coding=utf8
from flask import url_for

from models import AccessToken, WeixinTicket
from database import db
import time
import requests
from random import sample
from hashlib import sha1, sha256
import hmac
import logging

APP_ID = "wx636097f1cf66faa7"
APP_SEC = "2b84df7f797a35346e4706175d682991"

class AccessTokenService(object):
    def __init__(self, token, error=None):
        if error:
            self.error_msg = error
        else:
            self.token = token.get('access_token')
            self.error_msg = None
        self.ticket = ""
    
    @classmethod
    def try_grant(cls):
        ts = int(time.time())
        accessToken = AccessToken.query.filter().order_by(AccessToken.id.desc()).first()
        if accessToken:
            if (ts - accessToken.grand_ts < accessToken.expire):
                return AccessTokenService(dict(access_token=accessToken.access_token, expires_in=accessToken.expire))
        r = requests.get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s' % (APP_ID, APP_SEC))
        try:
            r.raise_for_status()
        except:
            return AccessTokenService(None, error=u"接口无法访问")
        resp = r.json()
        if "errcode" in resp and resp.get('errcode') > 0:
            return AccessTokenService(None, error=resp.get('errmsg'))
        db.add(AccessToken(access_token=resp.get('access_token'), expire=resp.get('expires_in'), grand_ts= ts-5))
        db.flush()
        db.commit()
        return AccessTokenService(resp)

    def getTicket(self):
        ts = int(time.time())
        weixinTicket = WeixinTicket.query.filter().order_by(WeixinTicket.id.desc()).first()
        if weixinTicket:
            if (ts - weixinTicket.grand_ts < weixinTicket.expire):
                self.ticket = weixinTicket.ticket
                return True, self.ticket
        r = requests.get('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi' % self.token)
        try:
            r.raise_for_status()
        except:
            return False, u"接口无法访问"
        resp = r.json()
        if "errcode" in resp and resp.get('errcode') > 0:
            return False, resp.get('errmsg')
        db.add(WeixinTicket(ticket=resp.get('ticket'), expire=resp.get('expires_in'), grand_ts= ts-5))
        db.flush()
        db.commit()
        self.ticket = resp.get('ticket')
        return True, self.ticket


    def sign(self, ts, url):
        nonce_seed = "qazxswedcvfrtgbnhyujmkiolp1234567890QAZXSWEDCVFRTGBNHYUJMKIOLP"
        self.nonce = "".join(sample(nonce_seed, 16))
        raw = dict(
            noncestr=self.nonce,
            jsapi_ticket=self.ticket,
            timestamp=ts,
            url=url
        )
        raw_str = "&".join(["%s=%s" % (k, v) for k, v in sorted(raw.iteritems(), key=lambda item: item[0])])
        hash = sha1()
        hash.update(raw_str)
        self.signitrue = hash.hexdigest()
        return self.signitrue, self.nonce

    def buySign(self, dt):
        sign_dt = [(k, v) for k, v in dt.iteritems() if k in ['appid', 'device_info', 'mch_id', 'nonce_str', 'body', 'out_trade_no', 'sign_type', 'total_fee', 'spbill_create_ip', 'notify_url', 'trade_type', 'openid']]
        key = "92ddc998fbc54a5ea3ca46795ce9f7c7"
        sign_dt = sorted(sign_dt, key=lambda item:item[0])
        sign_dt.append(('key', key))
        raw_str = "&".join(["%s=%s" % (k, v) for k, v in sign_dt])

        hash = hmac.new(key, raw_str, sha256)
        self.buy_sign = hash.hexdigest().upper()
        return self.buy_sign


    def buyItem(self, req_id, fee, ip, openid):
        nonce_seed = "qazxswedcvfrtgbnhyujmkiolp1234567890QAZXSWEDCVFRTGBNHYUJMKIOLP"
        self.nonce = "".join(sample(nonce_seed, 16))
        body = u"参赛报名费"
        payData = dict(
            appid = APP_ID,
            mch_id = "1499688332",
            device_info = "WEB",
            nonce_str = self.nonce,
            sign = "",
            sign_type = "HMAC-SHA256",
            body=body.encode('utf8'),
            out_trade_no="%032d" % (req_id + int(time.time())*10000000000),
            total_fee="%s" % fee,
            spbill_create_ip=ip,
            notify_url=url_for("www.notify_pay"),
            trade_type="JSAPI",
            openid=openid.encode('utf8'),
        )
        sign_rs = self.buySign(payData)
        payData["sign"] = sign_rs
        lines = ['<?xml version="1.0" encoding="UTF-8"?>']
        lines.append("<xml>")
        for key, value in payData.iteritems():
            lines.append("<%(key)s>%(value)s</%(key)s>" % dict(key=key, value=value))
        lines.append("</xml>")
        xml = "\n".join(lines)
        headers = {'Content-Type': 'application/xml'}
        r = requests.post("https://api.mch.weixin.qq.com/pay/unifiedorder", data=xml, headers=headers)
        try:
            r.raise_for_status()
        except:
            return False, u"接口无法访问"
        try:
            import xml.etree.cElementTree as ET
        except ImportError:
            import xml.etree.ElementTree as ET
        root = ET.fromstring(r.content)
        logging.error("but response:\n%s", r.content)
        executeRs = False
        payRs = False
        prepay_id = ""
        for child in root:
            if child.tag == "return_code" and child.text == "SUCCESS":
                executeRs = True
            if child.tag == "result_code" and child.text == "SUCCESS":
                payRs = True
            if child.tag == "prepay_id":
                prepay_id = child.text
        return executeRs and payRs, prepay_id

    def prepareBuy(self, prepay_id):
        nonce_seed = "qazxswedcvfrtgbnhyujmkiolp1234567890QAZXSWEDCVFRTGBNHYUJMKIOLP"
        self.nonce = "".join(sample(nonce_seed, 16))
        params = dict(
            appId = APP_ID,
            timeStamp = int(time.time()),
            nonceStr = self.nonce,
            package="prepay_id=%s" % prepay_id,
            signType="HMAC-SHA256"
        )
        sign_dt = [(k, v) for k, v in params.iteritems()]
        key = "92ddc998fbc54a5ea3ca46795ce9f7c7"
        sign_dt = sorted(sign_dt, key=lambda item: item [0])
        sign_dt.append(('key', key))
        raw_str = "&".join(["%s=%s" % (k, v) for k, v in sign_dt])
        logging.error("raw:%s", raw_str)
        hash = hmac.new(key, raw_str, sha256)
        _sign = hash.hexdigest().upper()
        params['paySign'] = _sign
        return params


        